package cn.highedu.coolshark.account.service.impl;

import cn.highedu.coolshark.account.mapper.AdminMapper;
import cn.highedu.coolshark.account.mapper.AdminRoleMapper;
import cn.highedu.coolshark.account.pojo.dto.AdminAddNewDTO;
import cn.highedu.coolshark.account.pojo.dto.AdminListParamPagedDTO;
import cn.highedu.coolshark.account.pojo.dto.AdminLoginInfoDTO;
import cn.highedu.coolshark.account.pojo.dto.AdminUpdateDTO;
import cn.highedu.coolshark.account.pojo.entity.Admin;
import cn.highedu.coolshark.account.pojo.entity.AdminRole;
import cn.highedu.coolshark.account.pojo.vo.*;
import cn.highedu.coolshark.account.security.JwtTokenHandler;
import cn.highedu.coolshark.account.security.UserDetailsImpl;
import cn.highedu.coolshark.account.service.IAdminService;
import cn.highedu.coolshark.common.EntityNotFoundException;
import cn.highedu.coolshark.common.PagedVO;
import cn.highedu.coolshark.common.ServiceCode;
import cn.highedu.coolshark.common.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 处理管理员数据的业务实现类
 *
 * @author java@tedu.cn
 * @version 0.0.1
 */
@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    /**
     * 注入认证管理器对象，在Spring Security的配置类中创建
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenHandler jwtTokenHandler;

    public AdminServiceImpl() {
        log.debug("创建业务类对象：AdminServiceImpl");
    }

    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        // 创建Admin对象
        Admin admin = new Admin();
        // 复制属性
        BeanUtils.copyProperties(adminAddNewDTO, admin);
        // 补全Admin对象的属性值：lastLoginIP(null) / loginCount(0) / gmtLastLogin(null)
        admin.setLoginCount(0);
        admin.setGmtCreate(LocalDateTime.now());
        // 从Admin对象中取出原密码，执行加密，再将密文存入到Admin对象中
        String rawPassword = admin.getPassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);
        admin.setPassword(encodedPassword);
        // 处理电话号码唯一约束异常
        try {
            // 调用Mapper对象的insert()执行插入
            int rows = adminMapper.insert(admin);
            if (rows != 1) {
                String message = "添加管理员失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_SAVE_FAILED, message);
            }
        } catch (DuplicateKeyException e) {
            log.error("添加管理员失败，发生异常 {} ", e.getClass());
            String message = "添加管理员失败，电话号码已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
    }

    @Override
    public void delete(Long id) {
        log.debug("开始处理【根据id删除管理员】的业务，参数：{}", id);
        // 检查尝试删除的是否为1号管理员
        if (id == 1) {
            String message = "删除管理员失败，不可以删除管理员！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 执行删除--管理员表
        log.debug("即将执行删除数据，参数：{}", id);
        int rows = adminMapper.deleteById(id);
        if (rows != 1) {
            String message = "删除管理员失败，ID不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE_FAILED, message);
        }
    }

    /**
     * 实现批量删除
     */
    @Override
    @Transactional // 事务控制 出现Runtime异常回滚
    public void delete(Long[] ids){
        log.debug("开始处理【根据id删除管理员】的业务，参数：{}", ids);
        if(ids == null || ids.length == 0) {
            return;
        }
        // 检查尝试删除的是否为1号管理员
        for (Long id : ids) {
            if (id == 1) {
                String message = "删除管理员失败，不可以删除管理员！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
            }
        }
        // 执行删除--管理员表
        log.debug("即将执行删除数据，参数：{}", ids);
        int rows = adminMapper.deleteByIds(ids);
        if (rows != ids.length) {
            String message = "删除管理员失败，ID不存在！";
            log.warn(message);
            //抛出异常 回滚事务
            throw new ServiceException(ServiceCode.ERR_DELETE_FAILED, message);
        }
    }

    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理【查询管理员列表】的业务，参数：无");
        List<AdminListItemVO> list = adminMapper.list();
        Iterator<AdminListItemVO> iterator = list.iterator();
        while (iterator.hasNext()) {
            AdminListItemVO item = iterator.next();
            if (item.getId() == 1) {
                iterator.remove();
                break;
            }
        }
        return list;
    }

    @Override
    public AdminStandardVO getAdminById(Long id) {
        log.debug("开始处理【根据id查询管理员详情】的业务，参数：{}", id);
        AdminStandardVO admin = adminMapper.getStandardById(id);
        if (admin == null) {
            String message = "查询管理员详情失败，ID不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        return admin;
    }

    @Override
    public void update(Long id, AdminUpdateDTO adminUpdateDTO) {
        log.debug("开始处理【修改管理员信息】的业务，参数：{}", adminUpdateDTO);
        // 创建Admin对象
        Admin admin = new Admin();
        admin.setId(id);
        // 复制属性
        BeanUtils.copyProperties(adminUpdateDTO, admin);
        // 补全Admin对象的属性值：gmtModified
        admin.setGmtModified(LocalDateTime.now());
        // 从Admin对象中取出原密码，执行加密，再将密文存入到Admin对象中
        if (adminUpdateDTO.getPassword() != null) {
            String rawPassword = adminUpdateDTO.getPassword();
            String encodedPassword = passwordEncoder.encode(rawPassword);
            admin.setPassword(encodedPassword);
        }
        // 处理电话号码唯一约束异常
        try {
            // 调用Mapper对象的insert()执行插入
            int rows = adminMapper.update(admin);
            if (rows != 1) {
                String message = "修改管理员失败，没有找到ID或者服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_UPDATE_FAILED, message);
            }
        } catch (DuplicateKeyException e) {
            log.error("修改管理员失败，发生异常 {} ", e.getClass());
            String message = "修改管理员失败，电话号码已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
    }

    @Override
    @Transactional
    public void addRoles(Long adminId, Long[] roleIds) {
        log.debug("开始处理【添加管理员角色】的业务，参数：adminId={}, roleIds={}", adminId, roleIds);
        // 检查adminId是否存在
        AdminStandardVO admin = adminMapper.getStandardById(adminId);
        if (admin == null) {
            String message = "添加管理员角色失败，管理员ID不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        // 检查roleIds是否存在 ...
        // 删除已经存在的关系
        adminRoleMapper.deleteByAdminId(adminId);
        // 批量添加新的关系
        List<AdminRole> adminRoles = new ArrayList<>();
        for (Long roleId : roleIds) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(adminId);
            adminRole.setRoleId(roleId);
            adminRoles.add(adminRole);
        }
        int rows = adminRoleMapper.insertBatch(adminRoles);
        if (rows != roleIds.length) {
            String message = "添加管理员角色失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_SAVE_FAILED, message);
        }
    }

    @Override
    public AdminLoginInfoVO getAdminLoginInfo(String username) {
        return adminMapper.getLoginInfoByUsername(username);
    }




    @Override
    public JwtVO login(AdminLoginInfoDTO adminLoginInfoDTO){
        //利用认证管理器手动认证
        //1.创建认证对象, 传入用户名和密码
        UsernamePasswordAuthenticationToken token =
                new UsernamePasswordAuthenticationToken(adminLoginInfoDTO.getUsername(),
                        adminLoginInfoDTO.getPassword());
        //2.调用认证管理器的authenticate方法, 传入认证对象（用户名和密码）
        Authentication authenticationResult = authenticationManager.authenticate(token);
        //3.认证成功后，将认证信息存入上下文，这样就完成了认证
        //  Spring安全上下文，存储了认证信息，就表示认证成功，认证信息就是Authentication对象
        //  相反，如果没有存储认证信息，就表示没有认证成功！这一点很重要！
        SecurityContextHolder.getContext().setAuthentication(authenticationResult);
        //获取认证的主体 principal
        Object principal = authenticationResult.getPrincipal();
        //认证主体实际是UserDetails的实现类 UserDetailsImpl
        UserDetailsImpl userDetails = (UserDetailsImpl) principal;
        //4.认证成功后，生成token
        String tokenString = jwtTokenHandler.createToken(userDetails);
        //5.将token返回给客户端
        return new JwtVO(tokenString);
    }

    /**
     * 登出
     */
    @Override
    public void logout(String jwtToken) {
        //清空上下文
        SecurityContextHolder.clearContext();
        //因为jwtToken还没有过期，为了避免jwtToken被盗用，将jwtToken加入黑名单
        //这样就可以在过滤器中检查jwtToken是否在黑名单中的，如果是，就拒绝访问
        //将token加入黑名单
        jwtTokenHandler.addLogoutBlacklist(jwtToken);
    }

    /**
     * 分页查询管理员列表
     * @param adminListParamPagedDTO 查询条件, 包含pageNum, pageSize, keyword
     * @return 管理员列表分页数据
     */
    @Override
    public PagedVO<AdminListItemVO> list(AdminListParamPagedDTO adminListParamPagedDTO){
        log.debug("开始处理【分页查询管理员列表】的业务，参数：{}", adminListParamPagedDTO);
        // 调用Mapper接口的方法查询数据
        List<AdminListItemVO> list = adminMapper.listByName(adminListParamPagedDTO);
        // 调用Mapper接口的方法查询符合条件的记录数
        int count = adminMapper.countByName(adminListParamPagedDTO);
        int pageSize = adminListParamPagedDTO.getPageSize();
        int pageNum = adminListParamPagedDTO.getPageNum();
        // 将结果封装到PagedVO对象中
        return new PagedVO<>(pageNum,pageSize,count,list);
    }

    /**
     * 启用/禁用
     * @param id 管理员id
     * @param enable 0-禁用, 1-启用
     */
    @Override
    public void changeEnable(Long id, Integer enable) {
        log.debug("开始处理【启用/禁用管理员】的业务，参数：id={}, enable={}", id, enable);
        // 检查id是否存在
        AdminStandardVO admin = adminMapper.getStandardById(id);
        if (admin == null) {
            String message = "启用/禁用管理员失败，管理员ID不存在！";
            log.warn(message);
            throw new EntityNotFoundException(message);
        }
        Admin adminForUpdate = new Admin();
        adminForUpdate.setId(id);
        adminForUpdate.setEnable(enable);
        adminForUpdate.setGmtModified(LocalDateTime.now());
        // 执行启用/禁用
        int rows = adminMapper.update(adminForUpdate);
        if (rows != 1) {
            String message = "启用/禁用管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE_FAILED, message);
        }
    }



}
